{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from dataclasses import dataclass, field\n",
    "\n",
    "\n",
    "@dataclass\n",
    "class Question:\n",
    "    question: str = field(metadata={\"desc\": \"The question asked by the user\"})\n",
    "    metadata: dict = field(\n",
    "        metadata={\"desc\": \"The metadata of the question\"}, default_factory=dict\n",
    "    )\n",
    "\n",
    "\n",
    "@dataclass\n",
    "class TrecData:\n",
    "    question: Question = field(\n",
    "        metadata={\"desc\": \"The question asked by the user\"}\n",
    "    )  # Required field, you have to provide the question field at the instantiation\n",
    "    label: int = field(\n",
    "        metadata={\"desc\": \"The label of the question\"}, default=0\n",
    "    )  # Optional field"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "TrecData(question=Question(question='What is the capital of France?', metadata={}), label=1)\n",
      "{'question': {'question': 'What is the capital of France?', 'metadata': {}}, 'label': 1}\n",
      "TrecData(question={'question': 'What is the capital of France?', 'metadata': {}}, label=1)\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "# dataclass itself is powerful, but it can not reconstruct nested dataclass\n",
    "example = TrecData(Question(\"What is the capital of France?\"), 1)\n",
    "print(example)\n",
    "\n",
    "from dataclasses import asdict\n",
    "\n",
    "print(asdict(example))\n",
    "reconstructed = TrecData(**asdict(example))\n",
    "print(reconstructed)\n",
    "print(reconstructed == example)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "non-default argument 'metadata' follows default argument",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[4], line 2\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[38;5;66;03m# it does not allow required field after optional field\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;129;43m@dataclass\u001b[39;49m\n\u001b[1;32m      3\u001b[0m \u001b[38;5;28;43;01mclass\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;21;43;01mTrecData2\u001b[39;49;00m\u001b[43m:\u001b[49m\n\u001b[1;32m      4\u001b[0m \u001b[43m    \u001b[49m\u001b[43mquestion\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mQuestion\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mfield\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m      5\u001b[0m \u001b[43m        \u001b[49m\u001b[43mmetadata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mdesc\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mThe question asked by the user\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m}\u001b[49m\n\u001b[1;32m      6\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# Required field, you have to provide the question field at the instantiation\u001b[39;49;00m\n\u001b[1;32m      7\u001b[0m \u001b[43m    \u001b[49m\u001b[43mlabel\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mfield\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m      8\u001b[0m \u001b[43m        \u001b[49m\u001b[43mmetadata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mdesc\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mThe label of the question\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdefault\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0\u001b[39;49m\n\u001b[1;32m      9\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# Optional field\u001b[39;49;00m\n",
      "File \u001b[0;32m/opt/homebrew/Cellar/python@3.11/3.11.6_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/dataclasses.py:1230\u001b[0m, in \u001b[0;36mdataclass\u001b[0;34m(cls, init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, slots, weakref_slot)\u001b[0m\n\u001b[1;32m   1227\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m wrap\n\u001b[1;32m   1229\u001b[0m \u001b[38;5;66;03m# We're called as @dataclass without parens.\u001b[39;00m\n\u001b[0;32m-> 1230\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mwrap\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mcls\u001b[39;49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/opt/homebrew/Cellar/python@3.11/3.11.6_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/dataclasses.py:1220\u001b[0m, in \u001b[0;36mdataclass.<locals>.wrap\u001b[0;34m(cls)\u001b[0m\n\u001b[1;32m   1219\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mwrap\u001b[39m(\u001b[38;5;28mcls\u001b[39m):\n\u001b[0;32m-> 1220\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_process_class\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mcls\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minit\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mrepr\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meq\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43morder\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43munsafe_hash\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1221\u001b[0m \u001b[43m                          \u001b[49m\u001b[43mfrozen\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmatch_args\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkw_only\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mslots\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1222\u001b[0m \u001b[43m                          \u001b[49m\u001b[43mweakref_slot\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/opt/homebrew/Cellar/python@3.11/3.11.6_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/dataclasses.py:1027\u001b[0m, in \u001b[0;36m_process_class\u001b[0;34m(cls, init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, slots, weakref_slot)\u001b[0m\n\u001b[1;32m   1022\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m init:\n\u001b[1;32m   1023\u001b[0m     \u001b[38;5;66;03m# Does this class have a post-init function?\u001b[39;00m\n\u001b[1;32m   1024\u001b[0m     has_post_init \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mhasattr\u001b[39m(\u001b[38;5;28mcls\u001b[39m, _POST_INIT_NAME)\n\u001b[1;32m   1026\u001b[0m     _set_new_attribute(\u001b[38;5;28mcls\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m__init__\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m-> 1027\u001b[0m                        \u001b[43m_init_fn\u001b[49m\u001b[43m(\u001b[49m\u001b[43mall_init_fields\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1028\u001b[0m \u001b[43m                                \u001b[49m\u001b[43mstd_init_fields\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1029\u001b[0m \u001b[43m                                \u001b[49m\u001b[43mkw_only_init_fields\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1030\u001b[0m \u001b[43m                                \u001b[49m\u001b[43mfrozen\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1031\u001b[0m \u001b[43m                                \u001b[49m\u001b[43mhas_post_init\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1032\u001b[0m \u001b[43m                                \u001b[49m\u001b[38;5;66;43;03m# The name to use for the \"self\"\u001b[39;49;00m\n\u001b[1;32m   1033\u001b[0m \u001b[43m                                \u001b[49m\u001b[38;5;66;43;03m# param in __init__.  Use \"self\"\u001b[39;49;00m\n\u001b[1;32m   1034\u001b[0m \u001b[43m                                \u001b[49m\u001b[38;5;66;43;03m# if possible.\u001b[39;49;00m\n\u001b[1;32m   1035\u001b[0m \u001b[43m                                \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43m__dataclass_self__\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mself\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mfields\u001b[49m\n\u001b[1;32m   1036\u001b[0m \u001b[43m                                        \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mself\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1037\u001b[0m \u001b[43m                                \u001b[49m\u001b[38;5;28;43mglobals\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1038\u001b[0m \u001b[43m                                \u001b[49m\u001b[43mslots\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1039\u001b[0m \u001b[43m                      \u001b[49m\u001b[43m)\u001b[49m)\n\u001b[1;32m   1041\u001b[0m \u001b[38;5;66;03m# Get the fields as a list, and include only real fields.  This is\u001b[39;00m\n\u001b[1;32m   1042\u001b[0m \u001b[38;5;66;03m# used in all of the following methods.\u001b[39;00m\n\u001b[1;32m   1043\u001b[0m field_list \u001b[38;5;241m=\u001b[39m [f \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m fields\u001b[38;5;241m.\u001b[39mvalues() \u001b[38;5;28;01mif\u001b[39;00m f\u001b[38;5;241m.\u001b[39m_field_type \u001b[38;5;129;01mis\u001b[39;00m _FIELD]\n",
      "File \u001b[0;32m/opt/homebrew/Cellar/python@3.11/3.11.6_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/dataclasses.py:545\u001b[0m, in \u001b[0;36m_init_fn\u001b[0;34m(fields, std_fields, kw_only_fields, frozen, has_post_init, self_name, globals, slots)\u001b[0m\n\u001b[1;32m    543\u001b[0m             seen_default \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m    544\u001b[0m         \u001b[38;5;28;01melif\u001b[39;00m seen_default:\n\u001b[0;32m--> 545\u001b[0m             \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnon-default argument \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mf\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m!r}\u001b[39;00m\u001b[38;5;124m \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m    546\u001b[0m                             \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mfollows default argument\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m    548\u001b[0m \u001b[38;5;28mlocals\u001b[39m \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m_type_\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mf\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m: f\u001b[38;5;241m.\u001b[39mtype \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m fields}\n\u001b[1;32m    549\u001b[0m \u001b[38;5;28mlocals\u001b[39m\u001b[38;5;241m.\u001b[39mupdate({\n\u001b[1;32m    550\u001b[0m     \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mMISSING\u001b[39m\u001b[38;5;124m'\u001b[39m: MISSING,\n\u001b[1;32m    551\u001b[0m     \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m_HAS_DEFAULT_FACTORY\u001b[39m\u001b[38;5;124m'\u001b[39m: _HAS_DEFAULT_FACTORY,\n\u001b[1;32m    552\u001b[0m     \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m__dataclass_builtins_object__\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;28mobject\u001b[39m,\n\u001b[1;32m    553\u001b[0m })\n",
      "\u001b[0;31mTypeError\u001b[0m: non-default argument 'metadata' follows default argument"
     ]
    }
   ],
   "source": [
    "# # it does not allow required field after optional field\n",
    "# @dataclass\n",
    "# class TrecData2:\n",
    "#     question: Question = field(\n",
    "#         metadata={\"desc\": \"The question asked by the user\"}\n",
    "#     ) # Required field, you have to provide the question field at the instantiation\n",
    "#     label: int = field(\n",
    "#         metadata={\"desc\": \"The label of the question\"}, default=0\n",
    "#     ) # Optional field\n",
    "#     metadata: dict = field(\n",
    "#         metadata={\"desc\": \"The metadata of the question\"}\n",
    "#     ) # required field"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# lets see what DataClass can do\n",
    "# 1. allow required field after optional field using required_field on default_factory\n",
    "\n",
    "from adalflow.core import DataClass, required_field\n",
    "\n",
    "\n",
    "@dataclass\n",
    "class TrecData2(DataClass):\n",
    "    question: Question = field(\n",
    "        metadata={\"desc\": \"The question asked by the user\"}\n",
    "    )  # Required field, you have to provide the question field at the instantiation\n",
    "    label: int = field(\n",
    "        metadata={\"desc\": \"The label of the question\"}, default=0\n",
    "    )  # Optional field\n",
    "    metadata: dict = field(\n",
    "        metadata={\"desc\": \"The metadata of the question\"},\n",
    "        default_factory=required_field(),\n",
    "    )  # required field"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "TrecData2(question=Question(question='What is the capital of France?', metadata={}), label=1, metadata={'key': 'value'})\n",
      "{'question': {'question': 'What is the capital of France?', 'metadata': {}}, 'label': 1, 'metadata': {'key': 'value'}}\n",
      "{'question': {'question': 'What is the capital of France?', 'metadata': {}}, 'label': 1, 'metadata': {'key': 'value'}}\n",
      "TrecData2(question=Question(question='What is the capital of France?', metadata={}), label=1, metadata={'key': 'value'})\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "# 2. allow you to reconstructed nested dataclass\n",
    "# You just have to make sure the class you are handling are subclass of DataClass, the child class can be native dataclass\n",
    "\n",
    "example = TrecData2(Question(\"What is the capital of France?\"), 1, {\"key\": \"value\"})\n",
    "print(example)\n",
    "\n",
    "dict_example = TrecData2.to_dict(example)  # use as if its a class method\n",
    "print(dict_example)\n",
    "\n",
    "dict_example_2 = example.to_dict()  # use it  as instance method\n",
    "print(dict_example)\n",
    "\n",
    "reconstructed = TrecData2.from_dict(dict_example)\n",
    "print(reconstructed)\n",
    "\n",
    "print(reconstructed == example)\n",
    "print(dict_example == dict_example_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'question': {'question': 'What is the capital of France?', 'metadata': {}}, 'label': 1}\n",
      "{'question': {'question': 'What is the capital of France?'}, 'label': 1}\n"
     ]
    }
   ],
   "source": [
    "# Lets exclude fields too\n",
    "\n",
    "# Note: better not to exclude required fields, as it will run issues using from_dict\n",
    "# you can use it if you dont mind to reconstruct\n",
    "\n",
    "# exclude field of only the parent class\n",
    "dict_exclude = example.to_dict(exclude=[\"metadata\"])\n",
    "print(dict_exclude)\n",
    "\n",
    "# exclude field of the parent and child class\n",
    "dict_exclude = example.to_dict(\n",
    "    exclude={\"TrecData2\": [\"metadata\"], \"Question\": [\"metadata\"]}\n",
    ")\n",
    "print(dict_exclude)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"question\": {\n",
      "        \"question\": \"What is the capital of France?\",\n",
      "        \"metadata\": {}\n",
      "    },\n",
      "    \"label\": 1,\n",
      "    \"metadata\": {\n",
      "        \"key\": \"value\"\n",
      "    }\n",
      "}\n",
      "question:\n",
      "  question: What is the capital of France?\n",
      "  metadata: {}\n",
      "label: 1\n",
      "metadata:\n",
      "  key: value\n",
      "\n",
      "TrecData2(question=Question(question='What is the capital of France?', metadata={}), label=1, metadata={'key': 'value'})\n",
      "True\n",
      "TrecData2(question=Question(question='What is the capital of France?', metadata={}), label=1, metadata={'key': 'value'})\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "# lets do the yaml and json string for demonstraing the data example\n",
    "\n",
    "json_str = example.to_json()\n",
    "print(json_str)\n",
    "\n",
    "yaml_str = example.to_yaml()\n",
    "print(yaml_str)\n",
    "\n",
    "reconstructed_from_json = TrecData2.from_json(json_str)\n",
    "print(reconstructed_from_json)\n",
    "print(reconstructed_from_json == example)\n",
    "\n",
    "reconstructed_from_yaml = TrecData2.from_yaml(yaml_str)\n",
    "print(reconstructed_from_yaml)\n",
    "print(reconstructed_from_yaml == example)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"question\": {\n",
      "        \"question\": \"What is the capital of France?\",\n",
      "        \"metadata\": {}\n",
      "    },\n",
      "    \"label\": 1,\n",
      "    \"metadata\": {\n",
      "        \"key\": \"value\"\n",
      "    }\n",
      "}\n",
      "question:\n",
      "  question: What is the capital of France?\n",
      "  metadata: {}\n",
      "label: 1\n",
      "metadata:\n",
      "  key: value\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# use with DataClassFormatType and format_example_str\n",
    "\n",
    "from adalflow.core import DataClassFormatType\n",
    "\n",
    "example_str = example.format_example_str(DataClassFormatType.EXAMPLE_JSON)\n",
    "print(example_str)\n",
    "\n",
    "example_str = example.format_example_str(DataClassFormatType.EXAMPLE_YAML)\n",
    "print(example_str)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'type': 'TrecData2',\n",
       " 'properties': {'question': {'type': \"{'type': 'Question', 'properties': {'question': {'type': 'str', 'desc': 'The question asked by the user'}, 'metadata': {'type': 'dict', 'desc': 'The metadata of the question'}}, 'required': ['question']}\",\n",
       "   'desc': 'The question asked by the user'},\n",
       "  'label': {'type': 'int', 'desc': 'The label of the question'},\n",
       "  'metadata': {'type': 'dict', 'desc': 'The metadata of the question'}},\n",
       " 'required': ['question', 'metadata']}"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Now, lets check the data format using class method without instance\n",
    "# schema, you can choose to only use properties\n",
    "\n",
    "schema = TrecData2.to_schema()\n",
    "schema"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'type': 'TrecData2',\n",
       " 'properties': {'question': {'type': \"{'type': 'Question', 'properties': {'question': {'type': 'str', 'desc': 'The question asked by the user'}}, 'required': ['question']}\",\n",
       "   'desc': 'The question asked by the user'},\n",
       "  'label': {'type': 'int', 'desc': 'The label of the question'}},\n",
       " 'required': ['question']}"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# schema with exclude\n",
    "schema_exclude = TrecData2.to_schema(\n",
    "    exclude={\"TrecData2\": [\"metadata\"], \"Question\": [\"metadata\"]}\n",
    ")\n",
    "schema_exclude"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"question\": \"The question asked by the user ({'type': 'Question', 'properties': {'question': {'type': 'str', 'desc': 'The question asked by the user'}, 'metadata': {'type': 'dict', 'desc': 'The metadata of the question'}}, 'required': ['question']}) (required)\",\n",
      "    \"label\": \"The label of the question (int) (optional)\",\n",
      "    \"metadata\": \"The metadata of the question (dict) (required)\"\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "# signature, json_signature\n",
    "\n",
    "json_signature = TrecData2.to_json_signature()\n",
    "print(json_signature)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"question\": \"The question asked by the user ({'type': 'Question', 'properties': {'question': {'type': 'str', 'desc': 'The question asked by the user'}}, 'required': ['question']}) (required)\",\n",
      "    \"label\": \"The label of the question (int) (optional)\"\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "# exclude field of the parent and child class\n",
    "\n",
    "json_signature_exclude = TrecData2.to_json_signature(\n",
    "    exclude={\"TrecData2\": [\"metadata\"], \"Question\": [\"metadata\"]}\n",
    ")\n",
    "print(json_signature_exclude)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"question\": \"The question asked by the user ({'type': 'Question', 'properties': {'question': {'type': 'str', 'desc': 'The question asked by the user'}, 'metadata': {'type': 'dict', 'desc': 'The metadata of the question'}}, 'required': ['question']}) (required)\",\n",
      "    \"label\": \"The label of the question (int) (optional)\"\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "# only exclude the parent class\n",
    "\n",
    "json_signature_exclude = TrecData2.to_json_signature(exclude=[\"metadata\"])\n",
    "print(json_signature_exclude)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "question: The question asked by the user ({'type': 'Question', 'properties': {'question': {'type': 'str', 'desc': 'The question asked by the user'}, 'metadata': {'type': 'dict', 'desc': 'The metadata of the question'}}, 'required': ['question']}) (required)\n",
      "label: The label of the question (int) (optional)\n",
      "metadata: The metadata of the question (dict) (required)\n"
     ]
    }
   ],
   "source": [
    "# signature, yaml_signature\n",
    "\n",
    "yaml_signature = TrecData2.to_yaml_signature()\n",
    "print(yaml_signature)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"question\": \"The question asked by the user ({'type': 'Question', 'properties': {'question': {'type': 'str', 'desc': 'The question asked by the user'}, 'metadata': {'type': 'dict', 'desc': 'The metadata of the question'}}, 'required': ['question']}) (required)\",\n",
      "    \"label\": \"The label of the question (int) (optional)\",\n",
      "    \"metadata\": \"The metadata of the question (dict) (required)\"\n",
      "}\n",
      "question: The question asked by the user ({'type': 'Question', 'properties': {'question': {'type': 'str', 'desc': 'The question asked by the user'}, 'metadata': {'type': 'dict', 'desc': 'The metadata of the question'}}, 'required': ['question']}) (required)\n",
      "label: The label of the question (int) (optional)\n",
      "metadata: The metadata of the question (dict) (required)\n",
      "{\n",
      "    \"type\": \"TrecData2\",\n",
      "    \"properties\": {\n",
      "        \"question\": {\n",
      "            \"type\": \"{'type': 'Question', 'properties': {'question': {'type': 'str', 'desc': 'The question asked by the user'}, 'metadata': {'type': 'dict', 'desc': 'The metadata of the question'}}, 'required': ['question']}\",\n",
      "            \"desc\": \"The question asked by the user\"\n",
      "        },\n",
      "        \"label\": {\n",
      "            \"type\": \"int\",\n",
      "            \"desc\": \"The label of the question\"\n",
      "        },\n",
      "        \"metadata\": {\n",
      "            \"type\": \"dict\",\n",
      "            \"desc\": \"The metadata of the question\"\n",
      "        }\n",
      "    },\n",
      "    \"required\": [\n",
      "        \"question\",\n",
      "        \"metadata\"\n",
      "    ]\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "# use the DataClassFormatType to control it\n",
    "\n",
    "from adalflow.core import DataClassFormatType\n",
    "\n",
    "json_signature = TrecData2.format_class_str(DataClassFormatType.SIGNATURE_JSON)\n",
    "print(json_signature)\n",
    "\n",
    "yaml_signature = TrecData2.format_class_str(DataClassFormatType.SIGNATURE_YAML)\n",
    "print(yaml_signature)\n",
    "\n",
    "schema = TrecData2.format_class_str(DataClassFormatType.SCHEMA)\n",
    "print(schema)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OutputFormat(thought=None, class_name='Entity', class_index=1)\n"
     ]
    }
   ],
   "source": [
    "# load with customizd from dict\n",
    "from typing import Dict\n",
    "\n",
    "\n",
    "@dataclass\n",
    "class OutputFormat(DataClass):\n",
    "    thought: str = field(\n",
    "        metadata={\n",
    "            \"desc\": \"Your reasoning to classify the question to class_name\",\n",
    "        }\n",
    "    )\n",
    "    class_name: str = field(metadata={\"desc\": \"class_name\"})\n",
    "    class_index: int = field(metadata={\"desc\": \"class_index in range[0, 5]\"})\n",
    "\n",
    "    @classmethod\n",
    "    def from_dict(cls, data: Dict[str, object]):\n",
    "        _COARSE_LABELS_DESC = [\n",
    "            \"Abbreviation\",\n",
    "            \"Entity\",\n",
    "            \"Description and abstract concept\",\n",
    "            \"Human being\",\n",
    "            \"Location\",\n",
    "            \"Numeric value\",\n",
    "        ]\n",
    "        data = {\n",
    "            \"thought\": None,\n",
    "            \"class_index\": data[\"coarse_label\"],\n",
    "            \"class_name\": _COARSE_LABELS_DESC[data[\"coarse_label\"]],\n",
    "        }\n",
    "        return super().from_dict(data)\n",
    "\n",
    "\n",
    "data = OutputFormat.from_dict({\"coarse_label\": 1})\n",
    "print(data)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "lightrag-project",
   "language": "python",
   "name": "light-rag-project"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
